/*
*    Qizx/open 3.0 beta
*
* This code is the open-source version of Qizx.
* Copyright (C) 2004-2009 Axyana Software -- All rights reserved.
*
* The contents of this file are subject to the Mozilla Public License 
*  Version 1.1 (the "License"); you may not use this file except in 
*  compliance with the License. You may obtain a copy of the License at
*  http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
*  WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
*  for the specific language governing rights and limitations under the
*  License.
*
* The Initial Developer of the Original Code is Xavier Franc - Axyana Software.
*
*/
using System;
using EvaluationException = System.Qizx.Api.EvaluationException;
using MatchOptions = System.Qizx.Queries.MatchOptions;
using PosFilters = System.Qizx.Queries.PosFilters;
using Selection = System.Qizx.Queries.Selection;
using EvalContext = System.Qizx.XQuery.EvalContext;
using Focus = System.Qizx.XQuery.Focus;
using ModuleContext = System.Qizx.XQuery.ModuleContext;
namespace System.Qizx.XQuery.Op
{
	
	/// <summary> Abstract Full-text selection (a list of terms or a boolean combination).
	/// Bears the options of a FT selection.
	/// </summary>
	public abstract class FTSelectionOp:Expression
	{
        public Expression[] children;

		public override int Flags
		{
			get
			{
				return Constant?Expression.CONSTANT:0;
			}
			
		}

        public void addChild(Expression child) {
            children = addExpr(children, child);
        }

		public override bool Constant
		{
			get
			{
				return (posFilters == null || posFilters.distance == null || posFilters.distance.Constant) && (posFilters == null || posFilters.windowExpr == null || posFilters.windowExpr.Constant) && (exp1 == null || exp1.Constant) && (exp2 == null || exp2.Constant);
			}
			
		}
		public FTSelectionOp exp1;
		public FTSelectionOp exp2;
		public Expression weight; // optional
		public FTPosFilters posFilters; // optional
		public MatchOptions matchOptions; // optional
		// occurs clause is only on words (why?)
		
		public FTSelectionOp(FTSelectionOp exp)
		{
            children = new Expression[] { exp };
		}

        public FTSelectionOp(Expression exp) {
            children = new Expression[] { exp };
        }

		public override Expression Child(int rank)
		{
			if (rank == 0)
				return exp1;
			if (rank == 1)
				return exp2;
			return null;
		}
		
		public override Expression StaticCheck(ModuleContext context, int flags)
		{
			exp1 = (FTSelectionOp) context.staticCheck(exp1, flags);
			exp2 = (FTSelectionOp) context.staticCheck(exp2, flags);
			if (posFilters != null)
			{
				posFilters.distance = (RangeExpr) context.staticCheck(posFilters.distance, 0);
				posFilters.windowExpr = context.staticCheck(posFilters.windowExpr, 0);
			}
			return this;
		}
		
		public abstract Selection expand(Focus focus, EvalContext context, MatchOptions inheritedMatchOptions, float inheritedWeight);
		
		/// <summary> Evaluates both 'Match options' and 'Position filters'.</summary>
		/// <param name="inherited">
		/// </param>
		/// <param name="heritedWeight">
		/// </param>
		protected internal virtual void  expandOptions(Selection s, Focus focus, EvalContext context, MatchOptions inherited, float heritedWeight)
		{
			s.MatchOptions = expandMatchOptions(inherited);
			s.setPosFilters(expandPositionFilters(focus, context));
			s.Weight = expandWeight(focus, context, heritedWeight);
		}
		
		protected internal virtual PosFilters expandPositionFilters(Focus focus, EvalContext context)
		{
			if (posFilters == null)
				return null;
			PosFilters pof = new PosFilters(posFilters);
			// eval distances, window
			if (posFilters.distance != null)
			{
				pof.distanceRange = posFilters.distance.evaluate(focus, context);
			}
			if (posFilters.windowExpr != null)
			{
				if (posFilters.windowUnit != PosFilters.WORDS)
					context.error("FT0001", this, "unsupported window unit");
				pof.window = (int) posFilters.windowExpr.evalAsInteger(focus, context);
			}
			return pof;
		}
		
		protected internal virtual MatchOptions expandMatchOptions(MatchOptions inherited)
		{
			MatchOptions mop = inherited; // if nothing defined locally
			if (matchOptions != null)
			{
				mop = new MatchOptions(matchOptions);
				// unspecified options are inherited:
				if (mop.language == null)
					mop.language = inherited.language;
				if (mop.caseSensitivity == MatchOptions.UNSPECIFIED)
					mop.caseSensitivity = inherited.caseSensitivity;
				if (mop.diacritics == MatchOptions.UNSPECIFIED)
					mop.diacritics = inherited.diacritics;
				if (mop.stemming == MatchOptions.UNSPECIFIED)
					mop.stemming = inherited.stemming;
				if (mop.wildcards == MatchOptions.UNSPECIFIED)
					mop.wildcards = inherited.wildcards;
				if (mop.thesauri == null)
					mop.thesauri = inherited.thesauri;
				//            if(mop.addedStopWords == null)
				//                mop.addedStopWords = inherited.addedStopWords;
				//            if(mop.exceptedStopWords == null)
				//                mop.exceptedStopWords = inherited.exceptedStopWords;
			}
			return mop;
		}
		
		protected internal virtual float expandWeight(Focus focus, EvalContext context, float inheritedWeight)
		{
			if (weight != null)
				return weight.evalAsFloat(focus, context);
			return inheritedWeight;
		}
	}
}